package com.neusoft.aclome.cmp.cloud.server;

import com.jp.protection.pub.LicenseImpl;
import com.neusoft.aclome.cmp.cloud.provider.client.CloudProviderClientContext;
import com.neusoft.aclome.cmp.cloud.provider.client.CloudProviderClientManager;
import com.neusoft.aclome.cmp.cloud.provider.client.CloudProviderManager;
import com.neusoft.aclome.cmp.cloud.provider.driver.HypervisorHostCloudDriver;
import com.neusoft.aclome.cmp.cloud.provider.model.HypervisorHostCloudEntity;
import com.neusoft.aclome.cmp.cloud.provider.options.HypervisorHostPageDataListOptions;
import com.neusoft.aclome.cmp.cloud.server.handler.cron.LicenseCheckCron;
import com.neusoft.aclome.cmp.cloud.server.model.entity.DataCenterEntity;
import com.neusoft.aclome.cmp.cloud.server.service.DataCenterService;
import com.neusoft.aclome.cmp.cloud.server.utils.DataCenterFactory;
import com.neusoft.aclome.cmp.common.model.entity.PageData;
import com.neusoft.aclome.cmp.common.task.TaskExecutor;
import com.neusoft.aclome.cmp.common.task.TaskFlow;
import com.neusoft.aclome.cmp.common.task.model.TaskFlowEntity;
import com.neusoft.aclome.cmp.common.task.service.TaskFlowService;
import com.neusoft.aclome.cmp.common.utils.SpringUtil;
import com.neusoft.aclome.cmp.license.ProtectionManager;
import com.neusoft.aclome.cmp.license.SecurityException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import tk.mybatis.spring.annotation.MapperScan;

import java.text.SimpleDateFormat;
import java.util.List;

@SpringBootApplication
@ComponentScan(basePackages = {"com.neusoft.aclome.cmp.cloud.*", "com.neusoft.aclome.cmp.common.*", "com.neusoft.pub.cloud.provider.*"})
@MapperScan({"com.neusoft.aclome.cmp.cloud.server.repository.database.mapper", "com.neusoft.aclome.cmp.common.task.mapper","com.neusoft.aclome.cmp.common.scheduler.mapper","com.neusoft.aclome.cmp.cloud.server.pub.cloud.repository","com.neusoft.aclome.cmp.cloud.server.jcce.repository"})
@EnableDiscoveryClient
@EnableTransactionManagement
@EnableFeignClients
@EnableCaching
@EnableScheduling   // 1.开启定时任务
@EnableAsync        // 2.开启多线程
public class AclomeCMPCloudServerApplication {

    private static Logger s_logger = LoggerFactory.getLogger(AclomeCMPCloudServerApplication.class);

    @Bean
    LicenseCheckCron getLicenseCron() {
        return new LicenseCheckCron();
    }


    public static void main(String[] args) {
        s_logger.info("Welcome to use SaCa Aclome CMP-cloud.");

        SpringApplication.run(AclomeCMPCloudServerApplication.class, args);

//        //初始化数据中心
//        DataCenterFactory.initDataCenter();
//
//        /*
//         * license存放多种方式 conf/
//         * 1、在conf默认路径下存放，如果重新启动无需考虑license路径问题，如果重新上传至conf路径下
//         * 2、通过系统环境变量指定位置，如果重启无需考虑license路径问题，如果重新上传需要上传到系统指定的环境变量的位置
//         *
//         * 校验时机：
//         * 1 程序启动，校验license是否有效和过期,校验网关IP --已完成
//         * 2 添加数据中心时，校验主机数量和虚拟化类型 --已校验数量，未校验虚拟化类型
//         * 3 删除数据中心时，刷新license校验状态，看缓存的物理主机限制状态是否有更改 --已完成
//         * 4 每天周期性的对当前的license进行校验，校验是否过期 --已完成，普通用户登陆已限制，超级管理员未限制（只显示一个菜单）
//         * 5 创建虚拟机之前如果超出主机数量限制，提示用户超出主机数量限制，无法创建虚拟机 --已完成
//         * 6 通过页面更新license时，触发license重新校验(当前只针对单cloud组件的更新替换操作) --已完成，license信息已更新同时异步更新资源校验未完成
//         * */
//        if (!ProtectionManager.getInstance().isLicenseValid()) {
//            try{
//                RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) SpringUtil.getBean("redisTemplate", RedisTemplate.class);
//                HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
//                hashOperations.put("CMP_ACCESS_CHECK", "LICENSE_STATUS", "LICENSE_INVALID");
//
//                refreshLicenseInfo();
//                s_logger.error("***************  License invalid, please check the expiration time of your license. ***************");
//            }catch (Exception e){
//                s_logger.error("*************** Load license info error. ***************", e);
//            }
//            System.exit(0);// 正常退出
//        } else {
//            RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) SpringUtil.getBean("redisTemplate", RedisTemplate.class);
//            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
//            hashOperations.put("CMP_ACCESS_CHECK", "LICENSE_STATUS", "LICENSE_VALID");
//
//            refreshLicenseInfo();
//
//            long currentHostSum = 0;
//            DataCenterService dataCenterService = SpringUtil.getBean(DataCenterService.class);
//            List<DataCenterEntity> dataCenterEntityList = dataCenterService.listDataCenter(false, true, false);
//            for (DataCenterEntity entity : dataCenterEntityList) {
//                try {
//                    HypervisorHostPageDataListOptions options = new HypervisorHostPageDataListOptions();
//                    options.setZoneUuid(entity.getFqn());
//                    options.setRegionUuid(entity.getRegionEntity().getFqn());
//
//                    PageData<HypervisorHostCloudEntity> hosts = getHypervisorHostCDriver(entity.getId()).listHypervisorHosts(options);
//                    currentHostSum += hosts.getTotalCount();
//                } catch (Exception e) {
//                    s_logger.warn("DataCenter({}) connection error", entity.getName());
//                }
//            }
//            s_logger.info("Access Cron currentHostSum: {}", currentHostSum);
//
//            String max = (String) hashOperations.get("CMP_ACCESS_CHECK", "ACLOME_BC_HOST_MAX");
//            if (StringUtils.isNotBlank(max)) {
//                long hostMaxLong = Long.valueOf(max);
//                if (currentHostSum > hostMaxLong) {
//                    SecurityException securityException = SecurityException.throwEx(new SecurityException.LICENSE_VALID_SCALE_LIMIT_EXCEPTION());
//                    hashOperations.put("CMP_ACCESS_CHECK", "LICENSE_STATUS", "LICENSE_VALID_SCALE_LIMIT_EXCEPTION");
//                    hashOperations.put("CMP_ACCESS_CHECK", "LICENSE_ERROR_CODE", securityException.getErrorCode());
//                    hashOperations.put("CMP_ACCESS_CHECK", "LICENSE_ERROR_MSG", securityException.getErrorMsgLocal());
//                } else {
//                    hashOperations.put("CMP_ACCESS_CHECK", "LICENSE_STATUS", "LICENSE_VALID");
//                    hashOperations.put("CMP_ACCESS_CHECK", "LICENSE_ERROR_CODE", "");
//                    hashOperations.put("CMP_ACCESS_CHECK", "LICENSE_ERROR_MSG", "");
//                }
//            }
//            s_logger.info("*************** License valid, continue... ***************");
//        }
//
//        //启动任务检查线程
//        TaskExecutor.getInstance();
//
//        //未完成任务状态修复
//        TaskFlowService flowService = SpringUtil.getBean(TaskFlowService.class);
//        List<TaskFlowEntity> flows = flowService.getUnFinishedTaskFlows();
//        flows.forEach(flow -> {
//            s_logger.info("unfinished task recovery, cancel task flow : name [ " + flow.getName() + " ], id [ " + flow.getId() + " ]");
//            try{
//                new TaskFlow(flow).cancel();
//            }catch (Exception e){
//                s_logger.warn("Task flow cancel error", e);
//            }
//        });
        s_logger.info("**********************************************************************");
    }

    private static HypervisorHostCloudDriver getHypervisorHostCDriver(Integer dataCenterId) {
        CloudProviderClientContext context = DataCenterFactory.getApiContext(dataCenterId);
        CloudProviderClientManager clientManager = CloudProviderManager.getCloudProviderClientManagerInstance();
        return (HypervisorHostCloudDriver) clientManager.getCloudDriver(context.getCloudProviderKey(), HypervisorHostCloudDriver.class);
    }

    private static void  refreshLicenseInfo(){
        try{
            final String PROJECT_SN = "project.sn"; //客户名称
            final String COMMON_USER = "common.customer"; //系统名称
            final String PROJECT_NAME = "project.name"; //产品版本 （直接从license获取）
            final String ACLOME_VERSION = "aclome.version";
            final String ACLOME_SUPPORT_VIRTUAL_PLATFORM = "aclome.support_virtual_platforms";
            final String ACLOME_BC_HOST_MAX = "aclome.bc.host.maxcount";
            final String IP_ADDRESSES = "ips";
            /**
             *  授权类型,值为企业版、开发版。
             *  当common.type 为deployment及unlimited 时，显示为企业版；
             *  当common.type - 为development时，显示为开发版。
             */
            final String COMMON_TYPE = "common.type";

            LicenseImpl aLicense = (LicenseImpl) ProtectionManager.getInstance().getLicense();
            RedisTemplate<String, Object> redisTemplate = (RedisTemplate<String, Object>) SpringUtil.getBean("redisTemplate", RedisTemplate.class);
            HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
            hashOperations.put("CMP_ACCESS_CHECK", "PROJECT_SN", aLicense.getProperties().get(PROJECT_SN));
            hashOperations.put("CMP_ACCESS_CHECK", "COMMON_USER", aLicense.getProperties().get(COMMON_USER));
            hashOperations.put("CMP_ACCESS_CHECK", "PROJECT_NAME", aLicense.getProperties().get(PROJECT_NAME));
            hashOperations.put("CMP_ACCESS_CHECK", "ACLOME_VERSION", aLicense.getProperties().get(ACLOME_VERSION));
            hashOperations.put("CMP_ACCESS_CHECK", "COMMON_TYPE", aLicense.getProperties().get(COMMON_TYPE));
            hashOperations.put("CMP_ACCESS_CHECK", "ACLOME_SUPPORT_VIRTUAL_PLATFORM", aLicense.getProperties().get(ACLOME_SUPPORT_VIRTUAL_PLATFORM));
            hashOperations.put("CMP_ACCESS_CHECK", "IP_ADDRESSES", aLicense.getProperties().get(IP_ADDRESSES));
            hashOperations.put("CMP_ACCESS_CHECK", "ACLOME_BC_HOST_MAX", aLicense.getProperties().get(ACLOME_BC_HOST_MAX));

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            hashOperations.put("CMP_ACCESS_CHECK", "ISSUE_DATE", sdf.format(aLicense.getLicenseIssueDate()));
            if (aLicense.getLicenseExpireDate() != null) {
                hashOperations.put("CMP_ACCESS_CHECK", "EXPIRE_DATE", sdf.format(aLicense.getLicenseExpireDate()));
            } else {
                hashOperations.put("CMP_ACCESS_CHECK", "EXPIRE_DATE", "");
            }
        } catch (Exception e){
            s_logger.info("Refresh LicenseInfo error", e);
        }
    }
}
